package com.yy.glide;

import com.yy.glide.recycle.Resource;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

public class ActiveResource {
    private Map<Key, ResourceWeakReference> mWeakReferenceMap = new HashMap<>();
    private ReferenceQueue<Resource> mReferenceQueue;
    private Thread mThread;
    private final Resource.ResourceListener mResourceListener;
    private boolean isShutDown;

    public ActiveResource(Resource.ResourceListener resourceListener) {
        mResourceListener = resourceListener;
    }

    /**
     * 加入活动缓存
     *
     * @param key
     * @param resource
     */
    public void active(Key key, Resource resource) {
        resource.setResourceListener(mResourceListener, key);
        mWeakReferenceMap.put(key, new ResourceWeakReference(key, resource, getReferenceQueue()));
    }

    public Resource removeActive(Key key) {
        ResourceWeakReference weakReference = mWeakReferenceMap.remove(key);
        if (weakReference.get() != null) {
            return weakReference.get();
        }
        return null;
    }

    public Resource get(Key key) {
        ResourceWeakReference reference = mWeakReferenceMap.get(key);
        if (reference != null) {
            return reference.get();
        }
        return null;
    }

    private ReferenceQueue<? super Resource> getReferenceQueue() {
        if (mReferenceQueue == null) {
            mReferenceQueue = new ReferenceQueue<>();
            mThread = new Thread() {
                @Override
                public void run() {
                    super.run();
                    while (!isShutDown) {
                        try {
                            ResourceWeakReference reference =
                                    (ResourceWeakReference) mReferenceQueue.remove();
                            mWeakReferenceMap.remove(reference.mKey);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

                }
            };
            mThread.start();
        }
        return mReferenceQueue;
    }

    void setShutDown() {
        isShutDown = true;
        if (mThread != null) {
            mThread.interrupt();
            try {
                mThread.join(TimeUnit.SECONDS.toMillis(5));
                if (mThread.isAlive()) {
                    throw new RuntimeException("fail to join time");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static final class ResourceWeakReference extends WeakReference<Resource> {
        final Key mKey;

        public ResourceWeakReference(Key key, Resource referent,
                                     ReferenceQueue<? super Resource> q) {
            super(referent, q);
            this.mKey = key;
        }
    }
}
